package com.pubinfo.passbook.common.service.ruler.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.pubinfo.passbook.common.entity.*;
import com.pubinfo.passbook.common.exception.ServiceException;
import com.pubinfo.passbook.common.mapper.*;
import com.pubinfo.passbook.common.model.bo.NormalInvoiceInfo;
import com.pubinfo.passbook.common.model.bo.rabbitmq.TbCert;
import com.pubinfo.passbook.common.model.bo.witeoff.CityInfo;
import com.pubinfo.passbook.common.model.bo.witeoff.InvoiceInfo;
import com.pubinfo.passbook.common.model.bo.witeoff.subitem.MedicineOnJobOrRetireSubitem;
import com.pubinfo.passbook.common.model.constant.City;
import com.pubinfo.passbook.common.model.constant.FannualDate;
import com.pubinfo.passbook.common.model.constant.StaffStatusEnum;
import com.pubinfo.passbook.common.model.dto.rule.RuleGenusParam;
import com.pubinfo.passbook.common.model.dto.witeoff.MedicineOnJobOrRetireDTO;
import com.pubinfo.passbook.common.model.dubbo.ESBServiceData;
import com.pubinfo.passbook.common.model.http.eip.UserInfo;
import com.pubinfo.passbook.common.model.http.request.GetWriteoffBaseData.GetWriteoffBaseDataItems;
import com.pubinfo.passbook.common.model.http.response.GetWriteoffBaseData.WriteoffBaseDataItem;
import com.pubinfo.passbook.common.model.http.response.GetWriteoffBaseData.WriteoffBaseDataOrgAndRole;
import com.pubinfo.passbook.common.model.ruler.Details;
import com.pubinfo.passbook.common.model.ruler.PayInformation;
import com.pubinfo.passbook.common.model.ruler.PersonInformation;
import com.pubinfo.passbook.common.model.ruler.UserAcc;
import com.pubinfo.passbook.common.service.dedicated.DedicatedService;
import com.pubinfo.passbook.common.service.dubbo.DubboService;
import com.pubinfo.passbook.common.service.master.*;
import com.pubinfo.passbook.common.service.mss.HttpService;
import com.pubinfo.passbook.common.service.ruler.CheckService;
import com.pubinfo.passbook.common.service.ruler.Enum.DetailsName;
import com.pubinfo.passbook.common.service.ruler.InformationService;
import com.pubinfo.passbook.common.service.ruler.RuleShengGongSiService;
import com.pubinfo.passbook.common.service.ruler.RuleWenZhouService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
@Primary
public class CheckServiceImpl implements CheckService  {
  @Autowired
  TPassbookService passbookService;
  @Autowired
  TSourceNormalService sourceNormalService;
  @Autowired
  InformationService informationService;
  @Autowired
  TRabbitmqPersonConvertService tRabbitmqPersonConvertService;
  @Autowired
  TSystemRoleService tSystemRoleService;
  @Autowired
  TRabbitmqOrgConvertService orgConvertService;
  @Autowired
  RuleWenZhouService wenZhouService;
  @Autowired
  TRuleRoleMapper ruleRoleMapper;
  @Autowired
  HttpService httpService;
  @Autowired
  DedicatedService dedicatedService;
  @Autowired
  TRuleUserWiteoffMapper witeoffMapper;
  @Autowired
  TRabbitmqOrgPersonMergeMapper tRabbitmqOrgPersonMergeMapper;
  @Autowired
  TRabbitmqOrgConvertMapper convertMapper;
  @Autowired
  TRuleFrequencyMapper frequencyMapper;
  @Autowired
  TRuleUserMapper userMapper;
  @Autowired
  TRabbitmqPersonService personService;
  @Autowired
  TRuleDiseasesMapper diseasesMapper;
  
  @Autowired
  TRuleFormulaMapper formulaMapper;
  @Autowired
  TRuleParamService paramService;
  @Autowired
  TRuleFrequencyService frequencyService;
  @Autowired
  DubboService dubboService;
  @Autowired
  TSourcePassbookMapper invoiceMapper;
  @Autowired
  TRuleGenusService genusService;
  @Autowired
  RuleShengGongSiService shengGongSiService;
  @Autowired
  TSubsidiaryInfoMapper infoMapper;
  @Autowired
  TRuleFormulaService formulaService;
  
  @Override
  public Map<String, List<TPassbook>> group(List<String> invoiceInfos) {
    Map<String, List<TPassbook>> resultMap = new HashMap<>();
    List<TPassbook> passbooks = this.passbookService.getPassbookById(invoiceInfos);
    if (CollectionUtils.isEmpty(passbooks)) {
      return resultMap;
    }
    
    List<TPassbook> genusOpcList = new ArrayList<>();
    List<TPassbook> genusHospitalizedList = new ArrayList<>();
    List<TPassbook> personnelOpcList = new ArrayList<>();
    List<TPassbook> personnelHospitalizedList = new ArrayList<>();
    for (TPassbook passbook : passbooks) {
      CityInfo info = this.infoMapper.findCityInfoByNsrsbh(passbook.getNsrsbh());
      InvoiceInfo invoiceInfo = this.invoiceMapper.invoiceInfoById(passbook.getId());
      Boolean isGenus = this.genusService.isGenus(invoiceInfo.getIdNo());
      //如果不是供属,则报账人即是票据付款人,如果是供属,则需查询供属表,关联出人员账号.
      String staffCode = this.getStaffCode(invoiceInfo.getIdNo(), isGenus);
      //如果员工状态不是在职,并且当前为供属报账,则不处理.
      ESBServiceData.CertDetail certDetail = this.dubboService.getPersonsDetailByIdNo(staffCode); //
      if (isGenus && !"在职".equals(certDetail.getStaffStatus())) {
        break;
      }
      //查询用户是否为特殊病种的用户
      Boolean isSpecialDiseases = this.isSpecialDiseases(info.getDistrictName(), passbook.getPayerPartyCode());
      if (isSpecialDiseases) {
        personnelHospitalizedList.add(passbook);
      } else {
        if ("330601".equals(passbook.getClassCode())) {
          
          if (isGenus) {
            genusOpcList.add(passbook);
          } else {
            personnelOpcList.add(passbook);
          }
        } else {
          if (isGenus) {
            genusHospitalizedList.add(passbook);
          } else {
            personnelHospitalizedList.add(passbook);
          }
        }
      }
    }
    resultMap.put("genusOpc", genusOpcList);
    resultMap.put("genusHospitalized", genusHospitalizedList);
    resultMap.put("personnelOpc", personnelOpcList);
    resultMap.put("personnelHospitalized", personnelHospitalizedList);
    return resultMap;
  }
  
  @Override
  public String getStaffCode(String idNo, Boolean isGenus) {
    String staffCode; //查询票据所有人的人员账号,如果是供属,则查询员工账号
    if (isGenus) {
      staffCode = this.genusService.findAcctByidNo(idNo);
    } else {
      staffCode = this.dubboService.getPersonsDetailByAcct(idNo);
    }
    return staffCode;
  }
  
  @Override
  public Boolean judgeRole(String roleCode, UserInfo userInfo) {

//    String jthrLoginName = userInfo.getJthrLoginName();
//    String acct = jthrLoginName.substring(0, jthrLoginName.indexOf("@"));
//
//    List<TSystemRole> roleList = tSystemRoleService.listCurrentUserRole(acct);
//    roleList = roleList.stream().filter(systemRole -> systemRole.getRoleCode().equals(roleCode)).collect(Collectors.toList());
  
    return roleCode.equals(userInfo.getRoleCode());
  }
  
  @Override
  public Boolean checkUserPermission(String acct, String acctCertNo, List<String> invoiceIds) throws DocumentException {
    return null;
  }
  
  @Override
  public Boolean isQuarterDate() {
    Calendar calendar = Calendar.getInstance();
    int march = calendar.get(Calendar.MARCH) + 1;
    int day = calendar.get(Calendar.DATE);
    if (FannualDate.DAY_FANNUAL == day) {
      switch (march) {
        case FannualDate.MARCH_TWELVE:
        case FannualDate.MARCH_SIX:
        case FannualDate.MARCH_THREE:
        case FannualDate.MARCH_NINE:
          return true;
        default:
          return false;
      }
    }
    return false;
  }
  
  @Override
  public Boolean isFannualDate(Integer type) {
    Calendar calendar = Calendar.getInstance();
    int march = calendar.get(Calendar.MARCH) + 1;
    int day = calendar.get(Calendar.DATE);
    if (type == null) {
      return false;
    }
    if (1 == type) {
      return FannualDate.MARCH_TWELVE == march && FannualDate.DAY_FANNUAL == day;
    } else {
      return FannualDate.MARCH_SIX == march && FannualDate.DAY_FANNUAL == day;
    }
  }
  
  private BigDecimal annualSumByDistrict(String nsrsbh, String idNo, Integer type) {
    CityInfo info = this.infoMapper.findCityInfoByNsrsbh(nsrsbh);
    BigDecimal annualSum = BigDecimal.ZERO;
    Class<? extends City.Type> clas = City.get(info.getCityName());
    if (clas.equals(City.Type.WenZhou.class)) {
      City.Type.WenZhou district = City.Type.WenZhou.get(info.getDistrictName());
      
      //如果是永嘉，在职与退休分开 门诊费有限制，住院没有限制
      if (City.Type.WenZhou.YONG_JIA.getName().equals(district.getName())) {
        //默认所有票据类型都是分开的
        if ("330601".equals(type)) {
          annualSum = new BigDecimal(10000);
        } else {
          annualSum = new BigDecimal(50000);
        }
      
      } else if (City.Type.WenZhou.LONG_GANG.getName().equals(district.getName())) {
        String statusName = this.dubboService.getPersonsDetailByStatus(idNo);
        Integer status = StaffStatusEnum.getEnumByStatus(statusName).getCode();
        //默认所有票据类型都是分开的
        if ("330601".equals(type)) {
          if (status.equals(0)) {
            annualSum = new BigDecimal(1500);
            //退休人员
          } else if (status.equals(1)) {
            //在职
            annualSum = new BigDecimal(3000);
          }
        } else {
          return annualSum;//住院没有限制
        }
      } else if (City.Type.WenZhou.RY_AN.getName().equals(district.getName())) {
        Boolean isSpecialDiseases = this.isSpecialDiseases(info.getDistrictName(), idNo);
        //默认所有票据类型都是分开的
        if (isSpecialDiseases) {
          annualSum = new BigDecimal(150000);
        } else {
          annualSum = new BigDecimal(180000);
        }
      }
    }
  
    return annualSum;
  }
  
  @Override
  public BigDecimal countWriteoff(MedicineOnJobOrRetireDTO jobDTO, Boolean isFront) {
//    jobDTO.setIsNeedAudit(true);
    TPassbook passbook = this.passbookService.getPassbookById(jobDTO.getInvoiceIds()).get(0);
    CityInfo info = this.infoMapper.findCityInfoByNsrsbh(passbook.getNsrsbh());
    BigDecimal sum = new BigDecimal(0);
    Class<? extends City.Type> clas = City.get(info.getCityName());
    String districtName = info.getDistrictName();
    //查询区县参数集
    Map<String, Object> paramEnv = this.paramService.selectRuleParam(info.getDisId());
    PayInformation payInformation = this.informationService.informationFromPassbook(jobDTO.getInvoiceIds());
    List<PayInformation> payInformations = this.informationService.listInformationFromPassbook(jobDTO.getInvoiceIds());
    String idNo = passbook.getPayerPartyCode(); //报账人的身份证号
    jobDTO.setIsSpecial(this.isSpecialDiseases(districtName, idNo));
    jobDTO.setIsSpecialUser(this.isSpecialUser(districtName, idNo));
    List<MedicineOnJobOrRetireSubitem> lineItems = jobDTO.getLineItems();
    //查询区县参数集
    BigDecimal outpatientDepartmentSum = new BigDecimal(0);
    BigDecimal outpatientDepartmentTotalAmount = new BigDecimal(0);
    BigDecimal hospitalizationSum = new BigDecimal(0);
    BigDecimal hospitalizationTotalAmount = new BigDecimal(0);
    BigDecimal reimburseSum = new BigDecimal(0);
    Map<String, TRuleFormula> ruleFormulaMap = formulaService.findFormulaByDistrictId(info.getDisId());
    paramEnv.putAll(ruleFormulaMap);
    if(!ObjectUtils.allNotNull(clas))
    {
      throw new ServiceException("该地区暂不支持报账");
    }
    if (clas.equals(City.Type.WenZhou.class)) {
      City.Type.WenZhou district = City.Type.WenZhou.get(districtName);
      switch (district) {
        case MUNICIPAL_LEVEL:
          reimburseSum = this.wenZhouService.municipalLevel(info, paramEnv, isFront, payInformations);
          break;
        case LONG_GANG:
          reimburseSum = this.wenZhouService.longGang(info, paramEnv, isFront, payInformations);
          break;
        case TAI_SHUN:
          reimburseSum = this.wenZhouService.taiShun(info, paramEnv, isFront, payInformations);
          break;
        case YUE_QING:
          reimburseSum = this.wenZhouService.yueQing(info, payInformations, paramEnv);
          break;
        case YONG_JIA:
          reimburseSum = this.wenZhouService.yongJia(info, paramEnv, isFront, payInformations);
          break;
        case CANG_NAN:
          reimburseSum = this.wenZhouService.cangNan(info, paramEnv, isFront, payInformations);
            break;
          case RY_AN:
            reimburseSum = this.wenZhouService.ruiAn(payInformations, paramEnv);
            break;
          case PING_YANG:
            reimburseSum = this.wenZhouService.pingYang(info, paramEnv, payInformations);
            break;
        default:
          reimburseSum = this.wenZhouService.municipalLevel(info, paramEnv, isFront, payInformations);
          break;
      }
      if (jobDTO.isProcessShort) {
        jobDTO.setIsNeedAudit(true);
      }
    } else if (clas.equals(City.Type.ShengGongSi.class)) {
      City.Type.ShengGongSi district = City.Type.ShengGongSi.get(districtName);
      //switch (district) { 省公司规则统一
      //  case BEN_BU:
//      reimburseSum = this.shengGongSiService.benbu(info, paramEnv, payInformations);
      reimburseSum = this.shengGongSiService.benbuNew(info, paramEnv, payInformations);
    }
    if ("330601".equals(passbook.getClassCode())) {
      outpatientDepartmentSum = outpatientDepartmentSum.add(reimburseSum);
      outpatientDepartmentTotalAmount = outpatientDepartmentTotalAmount.add(payInformation.getTotalAmount());
      jobDTO.setOutpatientDepartmentNub(jobDTO.getOutpatientDepartmentNub() + jobDTO.getInvoiceIds().size());
    } else {
      hospitalizationSum = hospitalizationSum.add(reimburseSum);
      hospitalizationTotalAmount = hospitalizationTotalAmount.add(payInformation.getTotalAmount());
      jobDTO.setHospitalizationNub(jobDTO.getHospitalizationNub() + jobDTO.getInvoiceIds().size());
    }
    payInformation.setReimbursableSum(reimburseSum);
    sum = sum.add(reimburseSum);
    outpatientDepartmentSum = outpatientDepartmentSum.setScale(2, RoundingMode.HALF_UP);
    outpatientDepartmentTotalAmount = outpatientDepartmentTotalAmount.setScale(2, RoundingMode.HALF_UP);
    hospitalizationSum = hospitalizationSum.setScale(2, RoundingMode.HALF_UP);
    hospitalizationTotalAmount = hospitalizationTotalAmount.setScale(2, RoundingMode.HALF_UP);
    jobDTO.setOutpatientDepartmentSum(outpatientDepartmentSum);
    jobDTO.setOutpatientDepartmentTotalAmount(outpatientDepartmentTotalAmount);
    jobDTO.setHospitalizationSum(hospitalizationSum);
    jobDTO.setHospitalizationTotalAmount(hospitalizationTotalAmount);
    //如果map中包含-0.0000999 ，则说明有些票据没有数据，则走人工审核
    Object isNeedAudit = paramEnv.get("isNeedAudit");
    if (isNeedAudit != null && (Boolean) isNeedAudit) {
      jobDTO.setIsNeedAudit(true);
    }
    Object detalis = paramEnv.get("user-detalis");
    jobDTO.setDetalis(info.getCityName() + "-" + districtName + "：" + detalis);
    //计算结果保留2位小数
    sum = sum.setScale(2, RoundingMode.HALF_UP);
    jobDTO.getPayInformations().add(payInformation);
    //   witeoffService
    for (MedicineOnJobOrRetireSubitem subitem : lineItems) {
      subitem.setSum(sum);
      subitem.setPriceSum(sum);
    }
    return sum;
  }
  
  @Override
  public Boolean isShengGongSi(List<TPassbook> passbookList) {
    //默认票据为同一个公司的票据
    List<String> nsrsbhs = new ArrayList<>();
    nsrsbhs.add("91330000MA27U07PX0");
    nsrsbhs.add("91330000744141180B");
    List<TPassbook> passbookFilter = passbookList.stream().filter(tPassbook -> nsrsbhs.contains(tPassbook.getNsrsbh())).collect(Collectors.toList());
    return !CollectionUtils.isEmpty(passbookFilter) && passbookFilter.size() == passbookList.size();
  }
  
  @Override
  public BigDecimal checkPassbookSum(MedicineOnJobOrRetireDTO jobDTO) {
    List<TPassbook> tPassbooks = passbookService.getPassbookById(jobDTO.getInvoiceIds());
    if (CollectionUtils.isEmpty(tPassbooks)) {
      return BigDecimal.ZERO;
    }
    TPassbook passbook = tPassbooks.get(0);
    String idNo = passbook.getPayerPartyCode(); //报账人的身份证号
    BigDecimal sum = this.countWriteoff(jobDTO, true);
    BigDecimal annualSum = this.annualSumByDistrict(passbook.getNsrsbh(), idNo, Integer.valueOf(passbook.getClassCode()));
    String acct = this.dubboService.getPersonsDetailByAcct(idNo);
    //查询本年度,历史报销金额
    BigDecimal historySum = this.witeoffMapper.countSumByAcct(acct, Integer.valueOf(passbook.getClassCode()));
    //如果限制金额为0,则直接返回计算后的金额
    if (annualSum.compareTo(BigDecimal.ZERO) == 0) {
      return sum;
    }
    if (historySum.add(sum).compareTo(annualSum) == 1) { //如果大于最大金额,则只能报账小于最大金额部分
      sum = annualSum.subtract(historySum);
    }
    return sum;
  }
  
  @Override
  public BigDecimal checkArtificialSum(CityInfo info, List<TSourceArtificial> artificialList) {
    if (CollectionUtils.isEmpty(artificialList)) {
      return BigDecimal.ZERO;
    }
    TSourceArtificial artificial = artificialList.get(0);
    QueryWrapper<TRuleFrequency> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("district_id", info.getDisId());
    List<TRuleFrequency> ruleFrequencies = this.frequencyService.list(queryWrapper);
    //计算总数
    BigDecimal sum = artificialList.stream().map(TSourceArtificial::getApprovedAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
    if (CollectionUtils.isEmpty(ruleFrequencies)) {
      return sum;//没有频次限制,默认通过
    }
    
    String idNo = this.personService.findIdNoByAcct(artificial.getAcct());
    BigDecimal annualSum = this.annualSumByDistrict(artificial.getNsrsbh(), idNo, artificial.getType());
    //查询本年度,历史报销金额
    BigDecimal historySum = this.witeoffMapper.countSumByAcct(artificial.getAcct(), artificial.getType());
    if (historySum.compareTo(BigDecimal.ZERO) == 1 && annualSum.compareTo(BigDecimal.ZERO) == 1 && historySum.add(sum).compareTo(annualSum) == 1) { //如果大于最大金额,则只能报账小于最大金额部分
      sum = annualSum.subtract(historySum);
    }
    return sum;
  }
  
  @Override
  public Boolean isReimbursementDate(String nsrsbh, String type, String idNo) {
    List<TRuleFrequency> ruleFrequencies = this.frequencyMapper.findAllByDistrictId(nsrsbh);
    //默认一个区县只有一条
    if (CollectionUtils.isEmpty(ruleFrequencies)) {
      return true;//没有频次限制,默认通过
    }
    TRuleFrequency ruleFrequency = ruleFrequencies.get(0);
    Calendar calendar = Calendar.getInstance();
    int march = calendar.get(Calendar.MARCH) + 1; //当前月份
    int day = calendar.get(Calendar.DATE);
    Integer periodType = ruleFrequency.getPeriodType();
    if (periodType == null || periodType == 0) {
      return true;//没有频次限制,默认通过
    }
    //如果是温州市本级特殊病,则直接放过
    CityInfo info = this.infoMapper.findCityInfoByNsrsbh(nsrsbh);
    City.Type.WenZhou district = City.Type.WenZhou.get(info.getDistrictName());
    //如果是永嘉，在职与退休分开 门诊费有限制，住院没有限制
    if (City.Type.WenZhou.MUNICIPAL_LEVEL.getName().equals(district.getName())) {
      Boolean isSpecialDiseases = this.isSpecialDiseases(info.getDistrictName(), idNo);
      if (isSpecialDiseases) {
        return true;
      }
    }
    if (ruleFrequency.getType().equals(type)) {
      if (ruleFrequency.getPeriodType() == 1) {
        //年度计算
        return ruleFrequency.getAnnualEndDate() == march && FannualDate.DAY_FANNUAL == day;
        
      } else if (ruleFrequency.getPeriodType() == 2) {
        //季度计算
        if (FannualDate.DAY_FANNUAL == day) {
          switch (march) {
            case FannualDate.MARCH_TWELVE:
            case FannualDate.MARCH_SIX:
            case FannualDate.MARCH_THREE:
            case FannualDate.MARCH_NINE:
              return true;
            default:
              return false;
          }
        }
      }
    }
    return true;
  }
  
  @Override
  public BigDecimal sumAll(List<String> invoiceIds) {
    List<NormalInvoiceInfo> normalInvoiceInfoList = this.sourceNormalService.selectListById(invoiceIds);
    List<TPassbook> passbookList = this.passbookService.getPassbookById(invoiceIds);
    BigDecimal sum = BigDecimal.ZERO;
    for (NormalInvoiceInfo normalInvoiceInfo : normalInvoiceInfoList) {
      sum = sum.add(new BigDecimal(normalInvoiceInfo.getJshj()));
    }
    for (TPassbook passbook : passbookList) {
      String passbookEinvoiceXml = passbook.getEinvoiceXml();
      sum = sum.add(this.getTotalAmountFromXml(passbookEinvoiceXml));
    }
    return sum;
  }
  
  private BigDecimal getTotalAmountFromXml(String xml) {
    Document document = null;
    try {
      document = DocumentHelper.parseText(xml);
    } catch (DocumentException e) {
      CheckServiceImpl.log.error("解析票据数据失败", e);
    }
    Element root = document.getRootElement().element("EInvoiceData");
    return new BigDecimal(root.element("Main").element("TotalAmount").getText());
  }
  /*判断所有发票类型是不是和前端传入的类型相同*/
  @Override
  public Boolean checkTypeIsNeed(Byte reimbursementType, List<String> idList) {
    //如果是住院，所有发票的代码都是330602
    List<TPassbook> passbookList = this.passbookService.getPassbookById(idList);
    if (reimbursementType == 1) {
      //所有数据类型一致且第一条数据的类型是330602
      return this.checkPassbookType(idList)
          && passbookList.get(0).getClassCode().equals("330602");
    }
    //如果是住院，所有发票的代码都是330601
    else if (reimbursementType == 0) {
      return this.checkPassbookType(idList)
          && passbookList.get(0).getClassCode().equals("330601");
    }
    return false;
  }
  /*
   统计诊察费自费+检查费自费+化验费自费+卫生材料费自费+中成药费自费+中药饮片费自费+西药费自费总数。
    */
  @Override
  public BigDecimal sumAmountSelf(List<Details> detailsList) {
    BigDecimal sum = BigDecimal.ZERO;
    
    for (Details details : detailsList) {
      
      if (EnumUtils.isValidEnum(DetailsName.class, details.getAuxItemRelatedName())) {
        sum = sum.add(new BigDecimal(details.getAmountSelf()));
      }
      
    }
    
    return sum;
  }
  
  @Override
  public BigDecimal sumAllTotalAmount(List<String> passbookIds) {
    List<PayInformation> payInformations = this.informationService.listInformationFromPassbook(passbookIds);
    return this.sumAllTotalAmountByPayInformations(payInformations);
  }
  
  @Override
  public BigDecimal sumAllTotalAmountByPayInformations(List<PayInformation> payInformations) {
    BigDecimal totalAmount = new BigDecimal(0);
    for (PayInformation payInformation : payInformations) {
      totalAmount = totalAmount.add(payInformation.getTotalAmount());
    }
    return totalAmount;
  }
  
  @Override
  public BigDecimal sumAllownPayAmount(List<PayInformation> payInformations) {
    
    BigDecimal sumAllownPayAmount = new BigDecimal(0);
    if (CollectionUtils.isEmpty(payInformations)) {
      
      return sumAllownPayAmount;
    }
    for (PayInformation payInformation : payInformations) {
      sumAllownPayAmount.add(payInformation.getOwnPayAmount());
    }
    return sumAllownPayAmount;
  }
  
  @Override
  public BigDecimal sumAllSelfpaymentCare(List<PayInformation> payInformations) {
    
    BigDecimal sumAllSelfpaymentCare = new BigDecimal(0);
    if (CollectionUtils.isEmpty(payInformations)) {
      
      return sumAllSelfpaymentCare;
    }
    for (PayInformation payInformation : payInformations) {
      sumAllSelfpaymentCare.add(payInformation.getSelfpaymentCare());
    }
    return sumAllSelfpaymentCare;
  }
  
  @Override
  public Boolean checkPassbookType(List<String> idList) {
    List<TPassbook> passbookList = this.passbookService.getPassbookById(idList);
    //没有获取到数组
    if (CollectionUtils.isEmpty(passbookList) || passbookList.size() != idList.size()) {
      return false;
    }
    //判断第一个数据是否是330601或330602
    if (!passbookList.get(0).getClassCode().equals("330601") && !passbookList.get(0).getClassCode().equals("330602")) {
      return false;
    }
    //判断是否所有数据的类型代码和第一个数据相同
    for (TPassbook passbook : passbookList) {
      if (!passbook.getClassCode().equals(passbookList.get(0).getClassCode())) {
        return false;
      }
    }
    return true;
  }
  
  @Override
  public Boolean checkPassbookPayer(List<String> idList, String acct) throws DocumentException {
    PersonInformation personInformation = this.informationService.GetPersonInformationFrom4A(acct);
    for (String id : idList) {
      PayInformation payInformation = this.informationService.GetInformationFromPassbook(id);
      if (!personInformation.getTbCert().getCertName().equals(payInformation.getPayerPartyName()) ||
          !personInformation.getTbCert().getCertNo().equals(payInformation.getPayerPartyCode())) {
        System.out.println(personInformation.getTbCert().getCertName() + " " + payInformation.getPayerPartyName());
        System.out.println(personInformation.getTbCert().getCertNo() + " " + payInformation.getPayerPartyCode());
        return false;
      }
    }
    return true;
  }
  
  @Override
  public BigDecimal getStartPayments(Map<String, Object> paramEnv, List<PayInformation> payInformations) {
    //获取最高级的报销金额
    BigDecimal startPayments = BigDecimal.ZERO;
    if (CollectionUtils.isEmpty(payInformations)) {
      return startPayments;
    }
    for (PayInformation payInformation : payInformations) {
      String startPayment = payInformation.getOrgType();
      if (startPayment.contains("三级")) {
        return new BigDecimal(String.valueOf(paramEnv.get("levelOneLine")));
      } else if (startPayment.contains("二级")) {
        startPayments = new BigDecimal(String.valueOf(paramEnv.get("levelTwoLine")));
      }
    }
    if (startPayments.compareTo(BigDecimal.ZERO) == 0) {
      return new BigDecimal(String.valueOf(paramEnv.get("levelThreeLine")));
    }
    return startPayments;
  }
  
  @Override
  public Boolean checkUserPower(List<PayInformation> payInformations, String acctId, String passbookAccId) {
    //如果他是部门报销员就可以报销部门下的所有人
    if ("passbook_reimbursement_clerk".equals(this.tSystemRoleService.selectRoleByAcct(acctId))) {
//            OrgTreeColleagueListParam orgTreeColleagueListParam = new OrgTreeColleagueListParam();
//            orgTreeColleagueListParam.setAcctId(Long.valueOf(acctId));
      //获取部门所有人员
      /**效率低*/
  
      return this.tRabbitmqOrgPersonMergeMapper.userSameOrg(passbookAccId, acctId) != 0;
    }
    //如果他不是部门报销员只能报销自己
    else {
      return passbookAccId.equals(acctId);
    }
  }
  
  @Override
  public Boolean isSpecialDiseases(String districtName, String idNo) {
    List<TRuleUser> userList = this.userMapper.findRuleRoleByCityName(districtName, idNo, 0);
    //如果没有查到,则返回false;
    return !CollectionUtils.isEmpty(userList);
  }
  
  @Override
  public Boolean isSpecialUser(String districtName, String idNo) {
    List<TRuleUser> userList = this.userMapper.findRuleRoleByCityName(districtName, idNo, 1);
    //如果没有查到,则返回false;
    return !CollectionUtils.isEmpty(userList);
  }
  
  @Override
  public Boolean isSpecialUser(String districtName, String idNo, String roleCode) {
    
    List<TRuleUser> userList = this.userMapper.findRuleUserByCityNameAndRoleCode(districtName, idNo, roleCode);
    return !CollectionUtils.isEmpty(userList);
  }
  
  @Override
  public List<PayInformation> getUserPassbookIdList(List<PayInformation> payInformations, PersonInformation personInformation) {
    List<PayInformation> payInformationList = new ArrayList<>();
    String employeeName = personInformation.getTbCert().getCertName();
    String employeeCode = personInformation.getTbCert().getCertNo();
    Map<String, String> personMap = new HashMap<>();
    //将报销人的身份证与姓名加入map，身份证为不会重复
    personMap.put(employeeCode, employeeName);
    for (PayInformation payInformation : payInformations) {
      //如果身份证和姓名与map中一致就是报销人员的票据
      if (personMap.containsKey(payInformation.getPayerPartyCode()) ||
          personMap.get(payInformation.getPayerPartyCode()).equals(payInformation.getPayerPartyName())) {
        payInformationList.add(payInformation);
      }
    }
    return payInformationList;
  }
  
  @Override
  public List<PayInformation> getGenusPassbookIdList(List<PayInformation> payInformations, PersonInformation personInformation) {
    List<PayInformation> payInformationList = new ArrayList<>();
    Map<String, String> personMap = new HashMap<>();
    RuleGenusParam ruleGenusParam = new RuleGenusParam();
    ruleGenusParam.setEmployeeName(personInformation.getTbCert().getCertName());
    List<TRuleGenus> genusList = this.genusService.selectRuleGenus(ruleGenusParam).getRecords();
    for (TRuleGenus ruleGenus : genusList) {
      //将供属的身份证和姓名加入map
      personMap.put(ruleGenus.getGenusCode(), ruleGenus.getGenusName());
    }
    for (PayInformation payInformation : payInformations) {
      //如果身份证和姓名与map中一致就是报销人员供属的票据
      if (personMap.containsKey(payInformation.getPayerPartyCode()) ||
          personMap.get(payInformation.getPayerPartyCode()).equals(payInformation.getPayerPartyName())) {
        payInformationList.add(payInformation);
      }
    }
    return payInformationList;
  }
  
  @Override
  public Boolean checkPassbookUser(List<PayInformation> payInformations, PersonInformation personInformation) {
    String employeeName = personInformation.getTbCert().getCertName();
    String employeeCode = personInformation.getTbCert().getCertNo();
    Map<String, String> personMap = new HashMap<>();
    //将报销人的身份证与姓名加入map，身份证为不会重复
    personMap.put(employeeCode, employeeName);
    RuleGenusParam ruleGenusParam = new RuleGenusParam();
    ruleGenusParam.setEmployeeName(employeeName);
    //获取该人的供属信息
    List<TRuleGenus> genusList = this.genusService.selectRuleGenus(ruleGenusParam).getRecords();
    for (TRuleGenus ruleGenus : genusList) {
      //将供属的身份证和姓名加入map
      personMap.put(ruleGenus.getGenusCode(), ruleGenus.getGenusName());
    }
    //任意取一条数据,用其身份证号过滤,如果不为空,则说明不是同一个人的票据
    List<PayInformation> filterPayInformations = payInformations.stream().filter(payInformation -> !payInformation.getPayerPartyCode().equals(payInformations.get(0).getPayerPartyCode())).collect(Collectors.toList());
    if (!CollectionUtils.isEmpty(filterPayInformations)) {
      return false;
    }
    for (PayInformation payInformation : payInformations) {
      //先判断有没有为这个身份证号的人，之后查看姓名是否对应
      if (!personMap.containsKey(payInformation.getPayerPartyCode()) ||
          !personMap.get(payInformation.getPayerPartyCode()).equals(payInformation.getPayerPartyName())) {
        return false;
      }
    }
    
    return true;
  }
  
  @Override
  public Boolean checkUserPermission(List<String> invoiceIds, String acctId) throws DocumentException {
    //如果用户是普通角色,则只能报销自己及供属家人的
    //如果是部门报销员,则只能报销所在部门及供属家人的
    PersonInformation personInformation = this.informationService.GetPersonInformationFrom4A(acctId);
    String employeeName = personInformation.getTbCert().getCertName();
    String employeeCode = personInformation.getTbCert().getCertNo();
    //储存身份证和姓名的对应关系（身份证不会重复所以用身份证做key）
    Map<String, String> personMap = new HashMap<>();
    personMap.put(employeeCode, employeeName);
    String roleCode = this.tSystemRoleService.selectRoleByAcct(acctId);
    if ("passbook_reimbursement_clerk".equals(roleCode)) {
//            OrgTreeColleagueListParam orgTreeColleagueListParam = new OrgTreeColleagueListParam();
//            orgTreeColleagueListParam.setAcctId(Long.valueOf(acctId));
//      List<TRabbitmqPersonConvert> tRabbitmqPersonConverts = this.tRabbitmqPersonConvertService.getPersonsByPersonOrgId(acctId);
//      for (TRabbitmqPersonConvert tRabbitmqPersonConvert : tRabbitmqPersonConverts) {
//        TbCert tbCert = tRabbitmqPersonConvert.getTbCert().get(0);
//        //添加公司人员的身份证和姓名
//        personMap.put(tbCert.getCertNo(), tbCert.getCertName());
//        //添加所有人员的眷属
//        RuleGenusParam ruleGenusParam = new RuleGenusParam();
//        ruleGenusParam.setEmployeeName(employeeName);
//        List<TRuleGenus> genusList = this.genusService.selectRuleGenus(ruleGenusParam).getRecords();
//        for (TRuleGenus ruleGenus : genusList) {
//          personMap.put(ruleGenus.getGenusCode(), ruleGenus.getGenusName());
//        }
      List<TRabbitmqPerson> tRabbitmqPeoples = this.personService.findDepartmentPersonByAcctId(acctId);
      for (TRabbitmqPerson tRabbitmqPeople : tRabbitmqPeoples) {
        TbCert tbCert = tRabbitmqPeople.getTbCert().get(0);
        //添加公司人员的身份证和姓名
        personMap.put(tbCert.getCertNo(), tbCert.getCertName());
        //添加所有人员的眷属
        RuleGenusParam ruleGenusParam = new RuleGenusParam();
        ruleGenusParam.setEmployeeName(employeeName);
        List<TRuleGenus> genusList = this.genusService.selectRuleGenus(ruleGenusParam).getRecords();
        for (TRuleGenus ruleGenus : genusList) {
          personMap.put(ruleGenus.getGenusCode(), ruleGenus.getGenusName());
        }
      }
    } else if ("passbook_reimbursement_clerk".equals(roleCode)) {
    
    } else {
    
      RuleGenusParam ruleGenusParam = new RuleGenusParam();
      ruleGenusParam.setEmployeeName(employeeName);
      List<TRuleGenus> genusList = this.genusService.selectRuleGenus(ruleGenusParam).getRecords();
      for (TRuleGenus ruleGenus : genusList) {
        personMap.put(ruleGenus.getGenusCode(), ruleGenus.getGenusName());
      }
    }
    for (String id : invoiceIds) {
      PayInformation payInformation = this.informationService.GetInformationFromPassbook(id);
      //先判断有没有为这个身份证号的人，之后查看姓名是否对应
      if (!personMap.containsKey(payInformation.getPayerPartyCode()) ||
          !personMap.get(payInformation.getPayerPartyCode()).equals(payInformation.getPayerPartyName())) {
        return false;
      }
    }
    return true;
  }
  
  //检查用户是否有权限报销
  @Override
  public Boolean checkUserPermission(String acctId, List<String> invoiceIds, String passbookAccId) throws DocumentException {
    List<PayInformation> payInformations = this.informationService.listInformationFromPassbook(invoiceIds);
    PersonInformation passbookPersonInformation = this.informationService.GetPersonInformationFrom4A(passbookAccId);
    //先验证票据是否是同一个人人的
    if (this.checkPassbookUser(payInformations, passbookPersonInformation)) {
      //验证登录用户是否有权限报销指定报销用户
      return this.checkUserPower(payInformations, acctId, passbookAccId);
    }
    return false;
  }
  
  @Override
  public UserAcc getUserAcc(String acct, Boolean isShow) {
    List<GetWriteoffBaseDataItems> account = new ArrayList<>();
    account.add(new GetWriteoffBaseDataItems(acct));
    List<WriteoffBaseDataItem> baseDataItems = this.dedicatedService.getWriteoffBaseDataItem(account).getItems();
    if (CollectionUtils.isEmpty(baseDataItems)) {
      //尝试使用@ZJ进行查询
      account.clear();
      account.add(new GetWriteoffBaseDataItems(acct + "@ZJ"));
      baseDataItems = this.dedicatedService.getWriteoffBaseDataItem(account).getItems();
    }
    if (!CollectionUtils.isEmpty(baseDataItems)) {
      List<WriteoffBaseDataOrgAndRole> orgAndRoles = baseDataItems.get(0).getWriteoffBaseDataOrgAndRoles();
      //如果只有一条,则直接返回,如果有多条,则查询4a数据,提取部门名称,关联后,再获取组织.
      if (orgAndRoles.size() > 1) {
        TRabbitmqPerson person = this.personService.selectByAcctId(acct);

//      //如果有多个组织，则通过人员查询过滤
        List<TRabbitmqOrgConvert> convertList = new LambdaQueryChainWrapper<>(convertMapper).in(TRabbitmqOrgConvert::getOrgId, person.getDepartmentCode()).list();
        //如果没有查到组织，则返回Null ,如果关联不上组织，则返回null
        if (!CollectionUtils.isEmpty(convertList)) {
          TRabbitmqOrgConvert convert = convertList.get(0);
          orgAndRoles = orgAndRoles.stream().filter(e -> e.getOrgCode().equalsIgnoreCase(convert.getMssCode())).collect(Collectors.toList());
      
        }
        if (CollectionUtils.isEmpty(convertList) || CollectionUtils.isEmpty(orgAndRoles)) {
          if (isShow) {
            throw new ServiceException(baseDataItems.get(0).getPrincipalName() + ",该人员没有配置组织信息，请联系系统管理员配置");
          }
          return null;
        }
      }
  
      return new UserAcc(baseDataItems.get(0), orgAndRoles.get(0));
    } else {
      //如果找不到人员账号,则直接报错
      if (isShow) {
        throw new ServiceException("没有找到" + acct + "员工的组织信息");
      }
    }
    return null;
  }

  @Override
  public Boolean haveVerticalPlate(List<String> invoiceIds) {
    List<TPassbook> passbooks= passbookService.getPassbookById(invoiceIds);
    Boolean re=false;
    for(TPassbook tPassbook:passbooks)
    {
      re=re || isVerticalPlate(tPassbook);
      System.out.println(re);
    }
    return re;
  }

  @Override
  public Boolean haveNonReimbursableItem(List<String> invoiceIds) {
    List<TPassbook> passbooks= passbookService.getPassbookById(invoiceIds);
    String regex=invoiceMapper.getRegular();
    Pattern pattern = Pattern.compile(regex);//编译正则表达式(\w+),?
    if(!CollectionUtils.isEmpty(passbooks))
    {
      for(TPassbook tPassbook:passbooks)
      {
        Matcher matcher = pattern.matcher(tPassbook.getEinvoiceXml());//用编译后的pattern去匹配目标字符串str
        if(matcher.find()){
          return true; //验证不通过
        }
      }
    }
    return false;
  }

  @Override
  public Boolean haveWrongAmount(List<PayInformation> payInformations) {

    for(PayInformation payInformation:payInformations)
    {
      if(!CollectionUtils.isEmpty(payInformation.getDetailList()))
      {
        for(Details details:payInformation.getDetailsList())
        {
          if(!"甲".equals(details.getType()) && BigDecimal.ZERO.compareTo(new BigDecimal(details.getAmountPercent()))==0)
          {
            return true;
          }
        }
      }
    }
    return false;
  }


  private Boolean isVerticalPlate(TPassbook tPassbook)
  {
    String xml = tPassbook.getEinvoiceXml();
    Document document = null;
    try {
      document = DocumentHelper.parseText(xml);
    } catch (DocumentException e) {
    }
    Element root = document.getRootElement();
    if(root.element("EInvoiceData").element("Main").element("MainExt").element("MedicalEInvoice")!=null)
    {
      return true;
    }
    if(root.element("EInvoiceData").element("Main").element("MainExt").element("OutMedicalExtInfo")!=null)
    {
      return true;
    }
    if(root.element("EInvoiceData").element("Main").element("InvoicingPartySeal")!=null)
    {
      return true;
    }
    return false;
  }

}
